package com.wolf.etl.core;

import com.wolf.etl.core.dialect.AbstractDialect;
import com.wolf.etl.enumeration.INFO_TYPE;
import com.wolf.etl.model.EtlRewriteBackModel;
import com.wolf.etl.model.EtlTableFilterModel;
import com.wolf.etl.model.EtlTableModel;
import com.wolf.etl.vo.BuildSqlParam;
import com.wolf.etl.vo.WriteBack;
import com.wolf.exception.WolfException;
import com.wolf.provider.util.StringUtils;
import com.wolf.util.DateUtil;
import com.wolf.vo.KeyValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author sdyang
 * @date 2019/10/7 16:18
 **/
@Service("WriteBackManager")
public class WriteBackManager {

    private static Logger logger = LoggerFactory.getLogger(WriteBackManager.class);

    private static final String logger_prefix = "wolf-etl#com.wolf.etl.core#WriteBackManager";


    private static final String SET_STR = "set";

    private static final String VALUE_STR = "value";

    private static final String UNDERSCORE = "_";

    protected static ETLManager etlManager;

    public static WriteBackManager getInstance(ETLManager etlManager) {
        WriteBackManager manager = new WriteBackManager();
        WriteBackManager.etlManager = etlManager;
        return manager;
    }


    public Map<String, String> writeBack(BuildSqlParam param, List<Object> values) {
        Map<String, String> sqls = new HashMap<>();

        AbstractDialect srcDialect = AbstractDialect.getInstance(etlManager, etlManager.getDataSourceDialet(etlManager.getSrcDataSourceId()));

        List<EtlRewriteBackModel> rs = etlManager.findRewriteBack();

        EtlTableModel etlTable = param.getSrcTable();
        KeyValuePair[] kvs = new KeyValuePair[rs.size()];

        for (int i = 0; i < rs.size(); i++) {
            KeyValuePair kv = new KeyValuePair();
            kv.setKey(rs.get(i).getColumn_name());
            kv.setValue(getWriteBackValue(rs.get(i).getColumn_value()));
            kvs[i] = kv;
        }


        for (int i = 0; i < values.size(); i++) {
            List<EtlTableFilterModel> filters = new ArrayList<>();
            EtlTableFilterModel filter = new EtlTableFilterModel();
            filter.setColumn_name(etlTable.getPrimary_key());
            filter.setFormula("=");
            filter.setColumn_value1(values.get(i).toString());
            filters.add(filter);

            String sql = srcDialect.buildUpdate(etlTable, kvs, filters);
            sqls.put(values.get(i).toString(), sql);
        }

        return sqls;

    }

    private String getWriteBackValue(String data) {

        if (StringUtils.isEmpty(data)) {
            return "";
        }

        // 日期
        if (data.contains("[TIME]${")) {
            return getTimeValue(data);
        }

        return data;
    }

    private String getTimeValue(String data) {
        if (!data.contains("[TIME]${")) {
            return data;
        }
        String var = data.substring(data.indexOf("[TIME]${") + 8, data.length() - 1);
        switch (var) {
            case "NOW":
                return DateUtil.getNow();
            default:
                return "";
        }
    }

    private void writeBack(String sql) {
        etlManager.appendSourceSql(sql);
    }

//    public BaseResult writeBack(Long tableId) {
//        BaseResult result = BaseResult.getSuccess();
//        EtlTableModel tableModel = etlManager.findEtlTableModel(tableId);
//        String alias = etlManager.getTableAlias(tableModel);
//        WriteBack writeBack = buildWriteBack(tableId);
//
//        AbstractDialect srcDialect = AbstractDialect.getInstance(etlManager,etlManager.getDataSourceDialet(etlManager.getSrcDataSourceId()));
//
//        String sql;
//        if (result.isSucc()) {
//            sql = srcDialect.buildUpdate(tableModel, writeBack.getSuccAttrKeyValuePairs());
//            writeBack(sql);
//            return result;
//        }
//
//        sql = srcDialect.buildUpdate(tableModel, writeBack.getFailAttrKeyValuePairs());
//        writeBack(sql);
//        return result;
//    }


    private WriteBack buildWriteBack(Long tableId) {
        WriteBack writeBack = new WriteBack();
        for (EtlTableFilterModel filterModel : etlManager.findEtlTableFilterModels(tableId)) {
            String infoType = filterModel.getInfo_type();
            if (StringUtils.isEmpty(infoType)) {
                throw new WolfException(String.format("The filter record[tab id=>%s] that it's info type value is empty.", tableId));
            }

            infoType = infoType.trim();
            infoType = infoType.replace(UNDERSCORE, "");

            for (Field field : WriteBack.class.getDeclaredFields()) {
                if (INFO_TYPE.contains(infoType)
                        && field.getName().equalsIgnoreCase(infoType)) {
                    assginWriteBackObject(filterModel, WriteBack.class, field, writeBack);
                }
            }
        }
        writeBack.check();
        return writeBack;
    }

    private void assginWriteBackObject(EtlTableFilterModel filterModel, Class clazz, Field field, WriteBack writeBack) {
        String methodName = SET_STR + StringUtils.firstLetterUpperCase(field.getName());
        try {
            java.lang.reflect.Method m = clazz.getMethod(methodName, new Class[]{String.class});
            m.invoke(writeBack, filterModel.getColumn_name());
            methodName = SET_STR + StringUtils.firstLetterUpperCase(field.getName()) + VALUE_STR;
            if (StringUtils.isEmpty(filterModel.getColumn_value1())) {
                throw new WolfException(String.format("Column  value of the filter model[id=>%s] is empty.", filterModel.getFilter_id()));
            }

            m = clazz.getMethod(methodName, new Class[]{String.class});
            m.invoke(writeBack, filterModel.getColumn_value1());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static String getSetStr() {
        return SET_STR;
    }

    public ETLManager getManager() {
        return etlManager;
    }

    public void setManager(ETLManager manager) {
        this.etlManager = manager;
    }

}
